package de.ba_rm.java.password.checker.view;

import info.clearthought.layout.TableLayout;
import info.clearthought.layout.TableLayoutConstants;
import info.clearthought.layout.TableLayoutConstraints;

import java.awt.Component;
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.basic.BasicComboBoxRenderer;

import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;

import de.ba_rm.java.password.checker.Controller;
import de.ba_rm.java.password.checker.Messages;
import de.ba_rm.java.password.checker.logic.config.Rule;
import de.ba_rm.java.password.checker.logic.config.RuleIO;

public class ConfigView extends JDialog {

	/** @see java.io.Serializable */
	private static final long serialVersionUID = 3552169835251365153L;
	
	private JComboBox ruleComboBox;
	
	private JTextField nameTextField;
	
	private JSpinner lengthSpinner;
	
	private JSpinner lowerCaseSpinner;
	
	private JSpinner upperCaseSpinner;
	
	private JSpinner caseSpinner;
	
	private JSpinner specialSpinner;
	
	private JSpinner numbersSpinner;
	
	private JSpinner specialBetweenCharSpinner;
	
	private JButton applyButton;

	private JButton saveButton;

	private Controller controller;
	
	public ConfigView(Controller controller, View owner) {
		super(owner);
		this.controller = controller;
		final String lastConfig = this.controller.getLastConfig();
		setTitle(Messages.getString("ConfigView.0")); //$NON-NLS-1$
		setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
		setLayout(initLayout());
		setResizable(false);
		init();
		setComboBoxDefaults(Controller.RULE);
		pack();
		setLocationRelativeTo(null);
		SwingUtilities.invokeLater(new Runnable() {
			@Override
			public void run() {
				try {
					loadComboBox(lastConfig);
				} catch (FileNotFoundException e) {
					throw new RuntimeException(e);
				}
			}
		});
		setVisible(true);
	}
	
	private LayoutManager initLayout() {
		final double p = TableLayoutConstants.PREFERRED;
		final double[] cols = new double[] {p, p};
		final double[] rows = new double[] {p, p, p, p, p, p, p, p, p, p};
		final TableLayout layout = new TableLayout(cols, rows);
		layout.setHGap(5);
		layout.setVGap(5);
		return layout;
	}

	private void init() {
		add(new JLabel(Messages.getString("ConfigView.1")), new TableLayoutConstraints(0, 0)); //$NON-NLS-1$
		add(getRuleComboBox(), new TableLayoutConstraints(1, 0));
		add(new JLabel(Messages.getString("ConfigView.11")), new TableLayoutConstraints(0, 1)); //$NON-NLS-1$
		add(getNameTextField(), new TableLayoutConstraints(1, 1));
		add(new JLabel(Messages.getString("ConfigView.2")), new TableLayoutConstraints(0, 2)); //$NON-NLS-1$
		add(getLengthSpinner(), new TableLayoutConstraints(1, 2));
		add(new JLabel(Messages.getString("ConfigView.3")), new TableLayoutConstraints(0, 3)); //$NON-NLS-1$
		add(getLowerCaseSpinner(), new TableLayoutConstraints(1, 3));
		add(new JLabel(Messages.getString("ConfigView.4")), new TableLayoutConstraints(0, 4)); //$NON-NLS-1$
		add(getUpperCaseSpinner(), new TableLayoutConstraints(1, 4));
		add(new JLabel(Messages.getString("ConfigView.5")), new TableLayoutConstraints(0, 5)); //$NON-NLS-1$
		add(getCaseSpinner(), new TableLayoutConstraints(1, 5));
		add(new JLabel(Messages.getString("ConfigView.6")), new TableLayoutConstraints(0, 6)); //$NON-NLS-1$
		add(getSpecialSpinner(), new TableLayoutConstraints(1, 6));
		add(new JLabel(Messages.getString("ConfigView.7")), new TableLayoutConstraints(0, 7)); //$NON-NLS-1$
		add(getNumbersSpinner(), new TableLayoutConstraints(1, 7));
		add(new JLabel(Messages.getString("ConfigView.8")), new TableLayoutConstraints(0, 8)); //$NON-NLS-1$
		add(getSpecialBetweenCharSpinner(), new TableLayoutConstraints(1, 8));
		add(getApplyButton(), new TableLayoutConstraints(0, 9));
		add(getSaveButton(), new TableLayoutConstraints(1, 9));
		
	}

	public JComboBox getRuleComboBox() {
		if (ruleComboBox == null) {
			ruleComboBox = new JComboBox();
			ruleComboBox.setRenderer(new BasicComboBoxRenderer() {
				
				/** @see java.io.Serializable */
				private static final long serialVersionUID = 1708147212229310042L;

				@Override
				public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
					if (value instanceof File) {
						setText(((File) value).getName());
					} else {
						setText(ObjectUtils.toString(value));
					}
					return this;
				}
			});
			ruleComboBox.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent e) {
					final JComboBox box = (JComboBox) e.getSource();
					if (box.getSelectedItem() instanceof File) {
						controller.actionRefresh((File) box.getSelectedItem());
						getNameTextField().setEnabled(false);
						getApplyButton().setEnabled(true);
					} else {
						getApplyButton().setEnabled(false);
						controller.initDefault();
					}
				}
			});
		}
		return ruleComboBox;
	}
	
	public JTextField getNameTextField() {
		if (nameTextField == null) {
			nameTextField = new JTextField(10);
		}
		return nameTextField;
	}

	public JSpinner getLengthSpinner() {
		if (lengthSpinner == null) {
			lengthSpinner = new JSpinner();
			lengthSpinner.addChangeListener(new DisableApplyButtonHandler());
		}
		return lengthSpinner;
	}

	public JSpinner getLowerCaseSpinner() {
		if (lowerCaseSpinner == null) {
			lowerCaseSpinner = new JSpinner();
			lowerCaseSpinner.addChangeListener(new DisableApplyButtonHandler());
		}
		return lowerCaseSpinner;
	}

	public JSpinner getUpperCaseSpinner() {
		if (upperCaseSpinner == null) {
			upperCaseSpinner = new JSpinner();
			upperCaseSpinner.addChangeListener(new DisableApplyButtonHandler());
		}
		return upperCaseSpinner;
	}

	public JSpinner getCaseSpinner() {
		if (caseSpinner == null) {
			caseSpinner = new JSpinner();
			caseSpinner.addChangeListener(new DisableApplyButtonHandler());
		}
		return caseSpinner;
	}

	public JSpinner getSpecialSpinner() {
		if (specialSpinner == null) {
			specialSpinner = new JSpinner();
			specialSpinner.addChangeListener(new DisableApplyButtonHandler());
		}
		return specialSpinner;
	}

	public JSpinner getNumbersSpinner() {
		if (numbersSpinner == null) {
			numbersSpinner = new JSpinner();
			numbersSpinner.addChangeListener(new DisableApplyButtonHandler());
		}
		return numbersSpinner;
	}

	public JSpinner getSpecialBetweenCharSpinner() {
		if (specialBetweenCharSpinner == null) {
			specialBetweenCharSpinner = new JSpinner();
			specialBetweenCharSpinner.addChangeListener(new DisableApplyButtonHandler());
		}
		return specialBetweenCharSpinner;
	}
	
	/**
	 * 
	 * @return
	 */
	public JButton getApplyButton() {
		if (applyButton == null) {
			applyButton = new JButton(Messages.getString("ConfigView.9")); //$NON-NLS-1$
			applyButton.setMnemonic(KeyEvent.VK_A);
			applyButton.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent e) {
					controller.actionApply();
				}
			});
		}
		return applyButton;
	}
	
	/**
	 * 
	 * @return
	 */
	public JButton getSaveButton() {
		if (saveButton == null) {
			saveButton = new JButton(Messages.getString("ConfigView.10")); //$NON-NLS-1$
			saveButton.setMnemonic(KeyEvent.VK_S);
			saveButton.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent e) {
					try {
						controller.actionSave();
					} catch (IOException ex) {
						throw new RuntimeException(ex);
					} finally {
						getApplyButton().setEnabled(true);
					}
				}
			});
		}
		return saveButton;
	}

	public void setComboBoxDefaults(final Rule rule) {
		getLengthSpinner().setModel(new SpinnerNumberModel(rule.getMinLength(), 0, Integer.MAX_VALUE, 1));
		getLowerCaseSpinner().setModel(new SpinnerNumberModel(rule.getNumLowerCase(), 0, Integer.MAX_VALUE, 1));
		getUpperCaseSpinner().setModel(new SpinnerNumberModel(rule.getNumUpperCase(), 0, Integer.MAX_VALUE, 1));
		getCaseSpinner().setModel(new SpinnerNumberModel(rule.getNumCase(), 0, Integer.MAX_VALUE, 1));
		getSpecialSpinner().setModel(new SpinnerNumberModel(rule.getNumSpecial(), 0, Integer.MAX_VALUE, 1));
		getNumbersSpinner().setModel(new SpinnerNumberModel(rule.getNumNumbers(), 0, Integer.MAX_VALUE, 1));
		getSpecialBetweenCharSpinner().setModel(new SpinnerNumberModel(rule.getNumSpecialBetweenChar(), 0, Integer.MAX_VALUE, 1));
	}
	
	public void loadComboBox(final String lastConfig) throws FileNotFoundException {
		getRuleComboBox().removeAllItems();
		getRuleComboBox().addItem(Messages.getString("ConfigView.12"));
		for (File file : RuleIO.loadRulesets()) {
			getRuleComboBox().addItem(file);
			if (file.getName().equalsIgnoreCase(StringUtils.trimToEmpty(lastConfig) + RuleIO.XML)) {
				getRuleComboBox().setSelectedItem(file);
			}
		}
	}
	
	private class DisableApplyButtonHandler implements ChangeListener {
		@Override
		public void stateChanged(ChangeEvent e) {
			getApplyButton().setEnabled(false);
		}
	}
}
